/*
 *  Copyright (C) 2010 Matthias Buch-Kromann <mbk.isv@cbs.dk>
 * 
 *  This file is part of the MatrixParser package.
 *  
 *  The MatrixParser program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 * 
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.osdtsystem.matrixparser.parsers;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import org.osdtsystem.matrixparser.data.GraphIterator;
import org.osdtsystem.matrixparser.featureextraction.FeatureExtractor;
import org.osdtsystem.matrixparser.features.DenseFeatureVector;
import org.osdtsystem.matrixparser.features.FeatureHandler;
import org.osdtsystem.matrixparser.features.FeatureVector;
import org.osdtsystem.matrixparser.features.MapFeatureHandler;
import org.osdtsystem.matrixparser.features.MapTwoWayFeatureHandler;
import org.osdtsystem.matrixparser.features.TwoWayFeatureHandler;
import org.osdtsystem.matrixparser.logging.Log;

/**
 *
 * @author Matthias Buch-Kromann <mbk.isv@cbs.dk>
 */
public class ParsingModel implements Serializable {
    // Feature handlers
    TwoWayFeatureHandler labelHandler;
    FeatureHandler featureHandler;

    // Weight vector
    DenseFeatureVector weights;
    transient FeatureVector ignoredFeatures;

    public ParsingModel() {
        labelHandler = new MapTwoWayFeatureHandler();
        featureHandler = new MapFeatureHandler();
        weights = new DenseFeatureVector();
        ignoredFeatures = null;
    }

    public ParsingModel(ParsingModel source) {
        labelHandler = source.labelHandler();
        featureHandler = source.featureHandler();
        weights = new DenseFeatureVector(source.weights.size());
        ignoredFeatures = source.ignoredFeatures();
    }

    public void fixWeights() {
        ignoredFeatures = new DenseFeatureVector();
        weights.addTo(1, ignoredFeatures);
    }

    public TwoWayFeatureHandler labelHandler() {
        return labelHandler;
    }

    public FeatureHandler featureHandler() {
        return featureHandler;
    }

    public DenseFeatureVector weights() {
        return weights;
    }

    public FeatureVector ignoredFeatures() {
        return ignoredFeatures;
    }

    public static ParsingModel load(File file) throws IOException, ClassNotFoundException {
        ParsingModel model = null;
        FileInputStream fis = null;
        ObjectInputStream in = null;
        fis = new FileInputStream(file);
        in = new ObjectInputStream(fis);
        model = (ParsingModel) in.readObject();
        in.close();
        return model;
    }

    public void save(File file) throws IOException {
        FileOutputStream fos = null;
        ObjectOutputStream out = null;
        fos = new FileOutputStream(file);
        out = new ObjectOutputStream(fos);
        out.writeObject(this);
        out.close();
    }

    public void growAlphabet(FeatureExtractor extractor, GraphIterator trainIterator) {
        // Grow alphabet for the gold features of each sentence
        Log.info("Growing alphabet...");
        long a = System.currentTimeMillis();
        int sent = 0;

        DenseFeatureVector mstFeatures = (iterations1 > 0 && iterations2 > 0)
                ? new DenseFeatureVector() : null;
        while(trainIterator.hasNext()) {
            CONLLSentence sentence = trainIterator.next();
            for (int i = 1; i < sentence.size(); ++i)
                model.labelHandler().getFeature(sentence.get(i).deprel());
            DependencyTree goldTree = incParser.goldTree(sentence);
            FeatureVector fv = incParser.featureVector(goldTree);
            if (mstFeatures != null)
                mstFeatures.add(mstParser.featureVector(goldTree));
            ++sent;
        }
        trainer.setSentences(sent);
        trainIterator.reset();
        model.featureHandler().stopGrowth();
        model.labelHandler().stopGrowth();
        CONLLIterator.stopGrowth();
        long b = System.currentTimeMillis();
        long t = (b - a) / 1000;
        System.gc();
        Log.info("   " + sent + " sentences [" + model.featureHandler().alphabetSize() + " features, " + t + " seconds" +
                    ", "+ ((int) ((Runtime.getRuntime().totalMemory()
                - Runtime.getRuntime().freeMemory()) / 1024 / 1024)) + " MB heap]");


    }
}
